home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / socks / sockd / sockd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-26  |  11.6 KB  |  603 lines

  1. #include <sys/types.h>
  2. #include <sys/time.h>
  3. #include <sys/socket.h>
  4. #include <sys/signal.h>
  5. #include <sys/syslog.h>
  6. #include <netinet/in.h>
  7. #include <arpa/inet.h>
  8. #include <sys/ioctl.h>
  9. #include <netdb.h>
  10. #include <stdio.h>
  11. #include <ctype.h>
  12. #include "socks.h"
  13.  
  14. #ifndef ntohb
  15. #define ntohb(x) x
  16. #endif
  17. #ifndef htonb
  18. #define htonb(x) x
  19. #endif
  20.  
  21. #define STREQ(a, b)    (strcasecmp(a, b) == 0)
  22.  
  23. #ifdef sun
  24. struct in_addr ipua;
  25. #endif /* #ifdef sun */
  26.  
  27. /*
  28. **  Current version for response messages
  29. */
  30. int        Version = 0;
  31.  
  32. die()
  33. {
  34.     exit(1);
  35. }
  36.  
  37. main(argc, argv)
  38. int    argc;
  39. char    **argv;
  40. {
  41.     char            buf[40], c;
  42.     int            inp, in, out, index=0;
  43.     int            n, len = sizeof(struct sockaddr_in);
  44.     struct sockaddr_in    sin, from, dstsin;
  45.     int            fromlen = sizeof(struct sockaddr_in);
  46.     Socks_t            dst;
  47.     int            one = 1;
  48.     char            buffer[20];
  49.  
  50.     if (openlog("sockd", LOG_PID, LOG_DAEMON) < 0)
  51.         ;
  52.  
  53. #ifdef INETD
  54.     inp  = socket(AF_INET, SOCK_STREAM, 0);
  55.     sin.sin_family = AF_INET;
  56.     sin.sin_port = htons(GetSocksPort());
  57.     sin.sin_addr.s_addr = htonl(INADDR_ANY);
  58.  
  59.     if (bind(inp, &sin, sizeof(sin)) < 0) {
  60.         syslog(LOG_ERR, "bind %m");
  61.         exit(1);
  62.     }
  63.  
  64.     if (listen(inp, 5) < 0) {
  65.         syslog(LOG_ERR, "listen %m");
  66.         exit(1);
  67.     }
  68.  
  69.     if ((in = accept(inp, &sin, &len)) < 0) {
  70.         syslog(LOG_ERR, "accept %m");
  71.         exit(1);
  72.     }
  73. #else
  74.     in = dup(0);
  75. #endif
  76.  
  77.     if (getpeername(in, &from, &fromlen) < 0) {
  78.         syslog(LOG_ERR, "Unable to get remote address");
  79.         exit(1);
  80.     }
  81.  
  82.     GetDst(in, &dst);
  83.  
  84.     dstsin.sin_family      = AF_INET;
  85.     dstsin.sin_addr.s_addr = dst.host;
  86.     dstsin.sin_port        = dst.port;
  87.     if (!Validate(&from, &dstsin)) {
  88. #ifdef sun
  89.         syslog(LOG_CRIT, "Invalid connection attempted from %s",
  90.                 inet_ntoa(from.sin_addr));
  91. #else
  92.         syslog(LOG_CRIT, "Invalid connection attempted from %s",
  93.                 inet_ntoa(from.sin_addr.s_addr));
  94. #endif /*#ifdef sun */
  95.         exit(1);
  96.     }
  97.     
  98.     /*
  99.     **  Kill a connecting off if bind or connect takes to
  100.     **    long to complete
  101.     */
  102.     signal(SIGALRM, die);
  103.     alarm(60*5);        /* 5 minutes */
  104.  
  105.     switch (Version = dst.version) {
  106. #ifdef SUPPORT_VERSION_1
  107.     case 1:
  108.         if (dst.cmd == SOCKS_CONNECT) 
  109.             DoConnect(in, &dst);
  110.         if (dst.cmd == SOCKS_BIND) 
  111.             DoBind(in, &dst);
  112.         break;
  113. #endif
  114. #ifdef SUPPORT_VERSION_2
  115.     case 2:
  116.         if (dst.cmd == SOCKS_CONNECT) 
  117.             DoConnect(in, &dst);
  118.         if (dst.cmd == SOCKS_BIND) 
  119.             DoNewBind(in, &dst);
  120.         break;
  121. #endif
  122.     case 3:
  123.         while (read(in, &c, 1) == 1)
  124.             if (c == '\0')
  125.                 break;
  126.             else if (index < sizeof(buf) - 1)
  127.                 buf[index++] = c;
  128.         buf[index] = '\0';
  129. #ifdef sun
  130.         strcpy(buffer,inet_ntoa(from.sin_addr));
  131.         ipua.s_addr = dst.host;
  132.         syslog(LOG_INFO, "%s from %s by %s to %s", 
  133.                 dst.cmd == SOCKS_CONNECT ? "Connect" : "Bind",
  134.                 buffer, buf, inet_ntoa(ipua));
  135. #else
  136.         strcpy(buffer,inet_ntoa(from.sin_addr.s_addr));
  137.         syslog(LOG_INFO, "%s from %s by %s to %s", 
  138.                 dst.cmd == SOCKS_CONNECT ? "Connect" : "Bind",
  139.                 buffer, buf, inet_ntoa(dst.host));
  140. #endif /* #ifdef sun */
  141.  
  142.         if (dst.cmd == SOCKS_CONNECT) 
  143.             DoConnect(in, &dst);
  144.         if (dst.cmd == SOCKS_BIND) 
  145.             DoNewBind(in, &dst);
  146.         break;
  147.     default:
  148.         syslog(LOG_ERR, "Version missmatch got %d\n", dst.version);
  149.         exit(1);
  150.     }
  151. }
  152.  
  153. int SendDst(s, dst)
  154. int     s;
  155. Socks_t *dst;
  156. {
  157.     Write8(s,  dst->version);
  158.     Write8(s,  dst->cmd);
  159.     Write32(s, dst->port);
  160.     Write32(s, dst->host);
  161. }
  162.  
  163. int GetDst(s, dst)
  164. int     s;
  165. Socks_t *dst;
  166. {
  167.     Read8(s,  dst->version);
  168.     Read8(s,  dst->cmd);
  169.     Read32(s, dst->port);
  170.     Read32(s, dst->host);
  171. }
  172.  
  173. /*
  174. ** Actually connect a socket to the outside world,
  175. */
  176. DoConnect(in, dst)
  177. int    in;
  178. Socks_t    *dst;
  179. {
  180.     int            out;
  181.     struct sockaddr_in    sin;
  182.     Socks_t            ndst;
  183.  
  184.     if ((out = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  185.         syslog(LOG_ERR, "out-socket %m\n");
  186.         exit(1);
  187.     }
  188.  
  189.     sin.sin_family = AF_INET;
  190.     sin.sin_port = dst->port;
  191.     sin.sin_addr.s_addr = dst->host;
  192.  
  193.     ndst.version = Version;
  194.     ndst.cmd = SOCKS_RESULT;
  195.  
  196.     if (connect(out, &sin, sizeof(struct sockaddr_in)) < 0) {
  197.         syslog(LOG_ERR, "DoConnect connect %m\n");
  198.         ndst.cmd = SOCKS_FAIL;
  199.         SendDst(in, &ndst);        exit(1);
  200.     }
  201.  
  202.     SendDst(in, &ndst);
  203.  
  204.     Pump(in, out);
  205. }
  206.  
  207. #ifdef SUPPORT_VERSION_1
  208. /*
  209. **  Set up a socket to be connected to from the outside world.
  210. */
  211. DoBind(in, dst)
  212. int    in;
  213. Socks_t    *dst;
  214. {
  215.     int            new, out, len = sizeof(struct sockaddr_in);
  216.     struct sockaddr_in    sin;
  217.     Socks_t            ndst;
  218.  
  219.     if ((out = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  220.         syslog(LOG_ERR, "out-socket %m\n");
  221.         exit(1);
  222.     }
  223.  
  224.     sin.sin_family = AF_INET;
  225.     ndst.version = Version;
  226.     ndst.cmd  = SOCKS_RESULT;
  227.     sin.sin_port = 0;
  228.     sin.sin_addr.s_addr = htonl(INADDR_ANY);
  229.  
  230.     if (bind(out, &sin, sizeof(sin)) < 0) {
  231.         syslog(LOG_ERR, "DoBind bind %m\n");
  232.         ndst.cmd = SOCKS_FAIL;
  233.         SendDst(in, &ndst);    exit(1);
  234.     }
  235.     if (getsockname(out, &sin, &len) < 0) {
  236.         syslog(LOG_ERR, "DoBind getsockname %m\n");
  237.         ndst.cmd = SOCKS_FAIL;
  238.         SendDst(in, &ndst);    exit(1);
  239.     }
  240.  
  241.     ndst.port = sin.sin_port;
  242.     ndst.host = sin.sin_addr.s_addr;
  243.  
  244.     if (listen(out, 1) < 0) {
  245.         syslog(LOG_ERR, "DoBind listen %m\n");
  246.         ndst.cmd = SOCKS_FAIL;
  247.         SendDst(in, &ndst);    exit(1);
  248.     }
  249.  
  250.     SendDst(in, &ndst);
  251.  
  252.     len = sizeof(struct sockaddr_in);
  253.     if ((new = accept(out, &sin, &len)) < 0) {
  254.         syslog(LOG_ERR, "DoBind accept %m\n");
  255.         ndst.cmd = SOCKS_FAIL;
  256.         SendDst(in, &ndst);    exit(1);
  257.     }
  258.  
  259.     ndst.port = sin.sin_port;
  260.     ndst.host = sin.sin_addr.s_addr;
  261.     SendDst(in, &ndst);
  262.  
  263.     Pump(in, new);
  264. }
  265. #endif /* SUPPORT_VERSION_1 */
  266.  
  267. /*
  268. **  Set up a socket to be connected to from the outside world.
  269. **   diffrence between this an the Version1 protocal is that
  270. **   the socket has to be bound from a specific host that
  271. **   is passed.
  272. */
  273. DoNewBind(in, dst)
  274. int    in;
  275. Socks_t    *dst;
  276. {
  277.     int            new, out, len = sizeof(struct sockaddr_in);
  278.     struct sockaddr_in    sin;
  279.     Socks_t            ndst;
  280.  
  281.     if ((out = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  282.         syslog(LOG_ERR, "out-socket %m\n");
  283.         exit(1);
  284.     }
  285.  
  286.     sin.sin_family = AF_INET;
  287.     ndst.version = Version;
  288.     ndst.cmd  = SOCKS_RESULT;
  289.     sin.sin_port = 0;
  290.     sin.sin_addr.s_addr = htonl(INADDR_ANY);
  291.  
  292.     if (bind(out, &sin, sizeof(sin)) < 0) {
  293.         syslog(LOG_ERR, "DoBind bind %m\n");
  294.         ndst.cmd = SOCKS_FAIL;
  295.         SendDst(in, &ndst);    exit(1);
  296.     }
  297.     if (getsockname(out, &sin, &len) < 0) {
  298.         syslog(LOG_ERR, "DoBind getsockname %m\n");
  299.         ndst.cmd = SOCKS_FAIL;
  300.         SendDst(in, &ndst);    exit(1);
  301.     }
  302.  
  303.     ndst.port = sin.sin_port;
  304.     ndst.host = sin.sin_addr.s_addr;
  305.  
  306.     if (listen(out, 1) < 0) {
  307.         syslog(LOG_ERR, "DoBind listen %m\n");
  308.         ndst.cmd = SOCKS_FAIL;
  309.         SendDst(in, &ndst);    exit(1);
  310.     }
  311.  
  312.     SendDst(in, &ndst);
  313.  
  314.     len = sizeof(struct sockaddr_in);
  315.     if ((new = accept(out, &sin, &len)) < 0) {
  316.         syslog(LOG_ERR, "DoBind accept %m\n");
  317.         ndst.cmd = SOCKS_FAIL;
  318.         SendDst(in, &ndst);    exit(1);
  319.     }
  320.  
  321.     if (sin.sin_addr.s_addr != dst->host) {
  322.         syslog(LOG_ERR, "DoBind Incorrect host 0x%08x 0x%08x  -- %m\n",
  323.                 sin.sin_addr.s_addr, dst->host);
  324.         ndst.cmd = SOCKS_FAIL;
  325.         SendDst(in, &ndst);    exit(1);
  326.     }
  327.  
  328.     ndst.port = sin.sin_port;
  329.     ndst.host = sin.sin_addr.s_addr;
  330.     SendDst(in, &ndst);
  331.  
  332.     Pump(in, new);
  333. }
  334.  
  335. /*
  336. **  Now just pump the packets/character through..
  337. */
  338. Pump(in, out)
  339. int    in, out;
  340. {
  341.     static char        buf[4096];
  342.     fd_set            fds;
  343.     int            n;
  344.     int            nfds = getdtablesize();
  345.     static struct timeval    tout = { 60*60*2, 0 };
  346.  
  347.     alarm(0);
  348.  
  349.     FD_ZERO(&fds);
  350.  
  351.     while (1) {
  352.         tout.tv_sec = SOCKS_TIMEOUT;
  353.         tout.tv_usec = 0;
  354.         FD_SET(in, &fds);
  355.         FD_SET(out, &fds);
  356.         if ((n = select(nfds, &fds, NULL, NULL, &tout)) > 0) {
  357.             if (FD_ISSET(in, &fds)) {
  358.                 if ((n = read(in, buf, sizeof buf)) > 0) {
  359.                     if (write(out, buf, n) < 0) {
  360.                         goto bad;
  361.                     }
  362.                 } else {
  363.                     goto bad;
  364.                 }
  365.             }
  366.             if (FD_ISSET(out, &fds)) {
  367.                 if ((n = read(out, buf, sizeof buf)) > 0) {
  368.                     if (write(in, buf, n) < 0) {
  369.                         goto bad;
  370.                     }
  371.                 } else {
  372.                     goto bad;
  373.                 }
  374.             }
  375.         } else {
  376.             if (n != 0)
  377.                 syslog(LOG_ERR, "select %m\n");
  378.             goto bad;
  379.         }
  380.     }
  381.  
  382. bad:
  383.     ;    /* Make the goto happy */
  384. }
  385.  
  386. /*
  387. **  Simple 'mkargs' doesn't handle \, ", or '.
  388. */
  389. void mkargs(cp, argc, argv, max)
  390. char    *cp;
  391. int    *argc;
  392. char    *argv[];
  393. int    max;
  394. {
  395.     *argc = 0;
  396.     while (isspace(*cp))
  397.         cp++;
  398.  
  399.     while (*cp != '\0') {
  400.         argv[(*argc)++] = cp;
  401.         if (*argc >= max)
  402.             return;
  403.  
  404.         while (!isspace(*cp) && (*cp != '\0'))
  405.             cp++;
  406.         while (isspace(*cp))
  407.             *cp++ = '\0';
  408.     }
  409. }
  410.  
  411. /* 
  412. **  Get address, either numeric or dotted quad, or hex.
  413. */
  414. int GetAddr(name, addr)
  415. char        *name;
  416. unsigned long    *addr;
  417. {
  418.     struct hostent    *hp;
  419.     struct netent    *np;
  420.  
  421.     if ((hp = gethostbyname(name)) != NULL) {
  422.         bcopy(hp->h_addr_list[0], addr, sizeof(*addr));
  423.         return *addr;
  424.     }
  425.     if ((np = getnetbyname(name)) != NULL) {
  426.         bcopy(&np->n_net, addr, sizeof(*addr));
  427.         return *addr;
  428.     }
  429.     return *addr = inet_addr(name);
  430. }
  431.  
  432. int GetPort(name)
  433. char        *name;
  434. {
  435.     struct servent    *sp;
  436.  
  437.     if ((sp = getservbyname(name, "tcp")) != NULL) {
  438.         return sp->s_port;
  439.     }
  440.     if (!isdigit(*name))
  441.         return -1;
  442.     return atoi(name);
  443. }
  444.  
  445. Validate(src, dst)
  446. struct sockaddr_in    *src, *dst;
  447. {
  448.     FILE        *fd;
  449.     static char    buf[1024];
  450.     char        *bp;
  451.     int        linenum = 0, permit, pos;
  452.     char        *argv[10];
  453.     int        argc, p;
  454.     unsigned long    saddr, smask, daddr, dmask;
  455.     unsigned short    dport;
  456.     enum         { e_lt, e_gt, e_eq, e_neq, e_nil } tst;
  457.  
  458. #ifdef DEBUG
  459.     syslog(LOG_ERR,"SRC: 0x%08x DST: 0x%08x",
  460.             src->sin_addr.s_addr, dst->sin_addr.s_addr);
  461. #endif
  462.  
  463.     if ((fd = fopen(SOCKS_CONF, "r")) == NULL) {
  464.         syslog(LOG_ERR, "Unable to open config file (%s)", SOCKS_CONF);
  465.  
  466.         return 0;
  467.     }
  468.  
  469.     while (fgets(buf, sizeof(buf) - 1, fd) != NULL) {
  470.         linenum++;
  471.         /*
  472.         **  Comments start with a '#' anywhere on the line
  473.         */
  474.         for (bp = buf; *bp != '\0'; bp++) {
  475.             if (*bp == '#') {
  476.                 *bp = '\0';
  477.                 break;
  478.             }
  479.             if ((*bp == '\t') || (*bp == '\t'))
  480.                 *bp = ' ';
  481.         }
  482.  
  483.         mkargs(buf, &argc, argv, 8);
  484.         if (argc == 0)
  485.             continue;
  486.         if ((argc < 3) || (argc > 7)) {
  487.             syslog(LOG_ERR, "Invalid entry at line %d", linenum);
  488.             continue;
  489.         }
  490.  
  491.         if (STREQ(argv[0], "permit")) {
  492.             permit = 1;
  493.         } else if (STREQ(argv[0], "deny")) {
  494.             permit = 0;
  495.         } else {
  496.             syslog(LOG_ERR, "Invalid permit/deny field at line %d", linenum);
  497.             continue;
  498.         }
  499.  
  500.         pos = 3;
  501.  
  502.         GetAddr(argv[1], &saddr);
  503.         GetAddr(argv[2], &smask);
  504.  
  505.         if ((saddr & smask) != 0) {
  506.             syslog(LOG_ERR, "Inavlid source address and mask pair at line %d", linenum);
  507.             continue;
  508.         }
  509.  
  510.         if ((argc > 4) &&
  511.             !(STREQ(argv[3], "eq") || STREQ(argv[3], "neq") ||
  512.               STREQ(argv[3], "lt") || STREQ(argv[3], "gt"))) {
  513.             GetAddr(argv[3], &daddr);
  514.             GetAddr(argv[4], &dmask);
  515.  
  516.             if ((daddr & dmask) != 0) {
  517.                 syslog(LOG_ERR, "Inavlid source address and mask pair at line %d", linenum);
  518.                 continue;
  519.             }
  520.             pos = 5;
  521.         } else {
  522.             daddr = 0;
  523.             dmask = ~0;
  524.             pos = 3;
  525.         }
  526.         if (argc > pos + 1) {
  527.             if (STREQ(argv[pos], "eq"))
  528.                 tst = e_eq;
  529.             else if (STREQ(argv[pos], "neq"))
  530.                 tst = e_neq;
  531.             else if (STREQ(argv[pos], "lt"))
  532.                 tst = e_lt;
  533.             else if (STREQ(argv[pos], "gt"))
  534.                 tst = e_gt;
  535.             else {
  536.                 syslog(LOG_ERR, "Invalid comparison at line %d", linenum);
  537.                 continue;
  538.             }
  539.                 
  540.             if ((p = GetPort(argv[pos+1])) == -1) {
  541.                 syslog(LOG_ERR, "Invalid port number at line %d", linenum);
  542.                 continue;
  543.             } else {
  544.                 dport = (unsigned short)p;
  545.             }
  546.         } else {
  547.             tst = e_nil;
  548.             dport = 0;
  549.         }
  550.  
  551. #ifdef DEBUG
  552.         {
  553.             char msg[1024];
  554.             sprintf(msg,"%s 0x%08x 0x%08x 0x%08x 0x%08x %s %d",
  555.                 permit ? "permit" : "deny",
  556.                 saddr, smask, daddr, dmask,
  557.                     tst == e_eq ? "==" :
  558.                     tst == e_neq ? "!=" :
  559.                     tst == e_lt ? "<" :
  560.                     tst == e_lt ? ">" : "NIL",
  561.                     dport);
  562.             syslog(LOG_ERR, "%s", msg);
  563.         }
  564. #endif
  565.  
  566.         if ((saddr & ~smask) == (src->sin_addr.s_addr & ~smask) &&
  567.             (daddr & ~dmask) == (dst->sin_addr.s_addr & ~dmask)) {
  568.             switch (tst) {
  569.             case e_eq:
  570.                 if (dport == dst->sin_port) {
  571.                     fclose(fd);
  572.                     return permit;
  573.                 }
  574.                 break;
  575.             case e_neq:
  576.                 if (dport != dst->sin_port) {
  577.                     fclose(fd);
  578.                     return permit;
  579.                 }
  580.                 break;
  581.             case e_lt:
  582.                 if (dport < dst->sin_port) {
  583.                     fclose(fd);
  584.                     return permit;
  585.                 }
  586.                 break;
  587.             case e_gt:
  588.                 if (dport > dst->sin_port) {
  589.                     fclose(fd);
  590.                     return permit;
  591.                 }
  592.                 break;
  593.             case e_nil:
  594.                 fclose(fd);
  595.                 return permit;
  596.             }
  597.         }
  598.     }
  599.  
  600.     fclose(fd);
  601.     return 0;
  602. }
  603.